<?php
namespace app\index\controller;


use app\index\model\GpsUtil;

class Index
{
    // 到站半径
    const IN_STATION_RADIUS = 100;



    public function index()
    {
        return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
    }

    public function test()
    {
//        $this->getLineInfos('31',0);
//        dump($data);
//        $gpsDao = model('Gps');
//        $datas = $gpsDao
//            ->where('line_no', 82)
//            ->where('bus_no', 1195)
//            ->order('time', 'asc')
//            ->select();
//        $this->displayArr($datas);

       $this->compareWithSTN(1195,0,3,0,1485900944);

//        echo $this->isValidTime(1485900764);
//        echo $this->isValidTime(1485938331);

        return "";
    }

    public function run()
    {

        //gps 工具
        $gpsUtil = new GpsUtil();

        $gpsDao = model('Gps');
        // 只查询82路
        $datas = $gpsDao->where('direction', '0')
            ->where('line_no', 82)
            ->where('bus_no', 1195)
            ->order('time', 'asc')
            ->select();

        $map = array();
        foreach ($datas as $d) {
            $busNo = $d['bus_no'];
            if (array_key_exists($busNo, $map)) {
                $map[$busNo]["number"] += 1;
                $d['lat'] /= 60;
                $d['lng'] /= 60;
//              二次存储时，计算相关站点信息。
                $currPosition = $d['next_station'] - 1;
                if ($currPosition == 1 || $currPosition == 2 || $currPosition == 3 || $currPosition == 4) {
//                    echo '当前车驶离第二站<br>';
                    $station = $map[$busNo]["lineInfos"][$currPosition - 1];
                    $stationNext = $map[$busNo]["lineInfos"][$currPosition];
//                    echo $station;
                    echo $busNo . " ";
                    $d = $gpsUtil->wgs2bd($d);
                    $dic = $gpsUtil->distance($d['lat'], $d['lng'], $station['lat'], $station['lng']);
                    $dicNext = $gpsUtil->distance($d['lat'], $d['lng'], $stationNext['lat'], $stationNext['lng']);
                    echo $currPosition . ' 距离所在站点(远离)：' . round($dic, 2);
                    echo $currPosition . ' 距离下一点(靠近)：' . $dicNext;
                    echo $currPosition . ' 总距离:' . round(($dic + $dicNext), 2);
                    echo " " . $this->ToTimeString($d['time']);
                    echo '<br>';
                    //距离当前站距离
                    $map[$busNo]['distance'] = $dic;
                }

                $map[$busNo]["lastInfos"] = $d;
            } else {
                $map[$busNo] = array();
                $map[$busNo]["number"] = 1;
                $d['lat'] /= 60;
                $d['lng'] /= 60;
                $map[$busNo]["lastInfos"] = $d;
                $map[$busNo]["firstInfos"] = $d;
//              判断线路号是否有效，无效的要记录
                $lineInfos = $this->getStationInfos($d["line_no"], $d['direction']);
                $map[$busNo]["lineInfos"] = $lineInfos;
//                next_station = (2,34),一共有34站，下一站信息只能统计到33站，
                // 即下一站为34时，有可能车已经到站了。
                // 当前车站点，如果当前车在 倒数第二站时，则有可能该车已到站了。
                $currPosition = $d['next_station'] - 1;


                echo ' 首次出现 No.' . $busNo;
                echo ' 当前所在站序号：(' . $currPosition . "/" . count($lineInfos) . ")";

                //当前站点非最后项
                if ($currPosition < count($lineInfos) - 1) {
                    $station = $lineInfos[$currPosition - 1];
                    $stationNext = $lineInfos[$currPosition];
//                    echo $station;
                    $d = $gpsUtil->wgs2bd($d);
                    $dic = $gpsUtil->distance($d['lat'], $d['lng'], $station['lat'], $station['lng']);
                    $dicNext = $gpsUtil->distance($d['lat'], $d['lng'], $stationNext['lat'], $stationNext['lng']);
                    echo '距离该点：' . $dic;
                    echo '距离下一点：' . $dicNext;
                    echo '总距离:' . ($dic + $dicNext);

                    //距离当前站距离
                    $map[$busNo]['distance'] = $dic;


                } else {

                }
                if ($lineInfos) {
                    echo " (" . $lineInfos[0]['line_name'] . ")";
                } else {
                    echo " (未找到匹配项，line_no是：" . $d["line_no"] . ") ";
                }
                echo '<br>';
            }
//            sleep(1);
        }
        echo '<br>';

        foreach ($map as $k => $val) {
            echo "车ID:" . $k . " 出现次数:" . $val["number"] . "首次上报时间：" . $this->ToDateTimeString($val["firstInfos"]['time']) . " 最后上报时间：" . $this->ToDateTimeString($val["lastInfos"]['time']) . "<br>";
        }
    }

    public function run1()
    {

        //gps 工具
        $gpsUtil = new GpsUtil();

        $gpsDao = model('Gps');
//        $db = db('');
        // 只查询82路
        $datas = $gpsDao
//            ->where('direction', '0')
            ->where('line_no', 82)
            ->where('bus_no', 1195)
            ->order('time', 'asc')
            ->select();

        //模拟内存，存放车辆信息
        $map = array();
        foreach ($datas as $d) {
            $busNo = $d['bus_no'];
            // 这里可以进行首次GPS过滤，如不在系统统计时间，直接跳过

            // 处理原始数据
            $d = $this->processGps($d);

            if ($this->isValidGps($d)) {

                // 该车是否出现过
                if (array_key_exists($busNo, $map)) {
                    $map[$busNo]["number"] += 1;
//              二次存储时，计算相关站点信息。
                    $currPosition = $d['next_station'] - 1;
                    $lineInfos = null;
                    if(array_key_exists('dir'.$d['direction'],$map[$busNo])){
                        $lineInfos = $map[$busNo]['dir'.$d['direction']]["lineInfos"];
                    }else {
                        $lineInfos = $this->getStationInfos($d["line_no"], $d['direction']);
                        $map[$busNo]['dir'.$d['direction']]["lineInfos"] = $lineInfos;
                    }

//                    查找最近站点信息，通过gps
                    $stations = $this->getLatestStations($lineInfos, $d['lat'], $d['lng']);
//                    $this->displayArr($stations);

//                    ($stations);
                    //距离最近站在100米之内，则认为到达该站了
                    if ($stations[0]['dictance'] < $this::IN_STATION_RADIUS) {

                        $map[$busNo]["index"] = $stations[0]['station_no'];
                        // 到站了

                        $map[$busNo]['lastStations'] = $stations;


                        // 明确到站，可以跟stn表比对
                        if(!$map[$busNo]["inStation"]){
                            echo "<br>" . $busNo . " ";
//                        echo " " . $currPosition;
                            echo " 到达了 " . $stations[0]['station_no'] . " " . $stations[0]['station_name'];
                            echo " 距离该点 " . $stations[0]['dictance'];
                            echo " " . $this->ToTimeString($d['time']) . "(" . $d['time'] . ")";
                            $this->compareWithSTN($busNo,$d['direction'],$map[$busNo]["index"],0,$d['time']);
                        }
                        $map[$busNo]["inStation"] = true;
                    } else {

                        // 有到站信息
                        if (array_key_exists('index', $map[$busNo])) {

                            //离站了
                            $stationIndex = $map[$busNo]['index'];
                            //比较当前站点序号与最近站点序号
                            if ($stationIndex == $stations[0]['station_no']) {
                                // 刚驶离最近站点，

                                // 明确离站，可跟stn比对
                                if($map[$busNo]["inStation"]){
                                    echo "<br>" . $busNo . " ";
//                                    echo " " . $currPosition;
                                    echo " 离开了 " . $stationIndex . " " . $stations[0]['station_name'] . '(前半段)';
                                    echo " 距离该点 " . $stations[0]['dictance'];
                                    echo " " . $this->ToTimeString($d['time']) . "(" . $d['time'] . ")";

                                    $this->compareWithSTN($busNo,$d['direction'],$map[$busNo]["index"],1,$d['time']);
                                }
                            }
                            else if (($stations[0]['station_no'] - $stationIndex) == 1) {
                                //正在靠近最近站点
                                //echo "<br>" . $busNo . " ";
//                                echo " " . $currPosition;
//                                echo " 离开了 " . $stationIndex . " 靠近了" . $stations[0]['station_name'] . '(后半段)';
//                                echo " 距离该点 " . $stations[0]['dictance'];

                            }
                            else {
                                // 站点序号与上一次不一致。
                                // 比较时间，时间太久则重置数据
                                // 比较站号，
//                                    dump($map[$busNo]["lastInfos"]);
                                $lastTime = $map[$busNo]["lastInfos"]["time"];
                                $offTime = $d['time'] - $lastTime;
                                // 两次汇报超过1分钟，重新设置站点序号，可能由于车辆gps未成功上报导致
                                if ($offTime > 60) {
                                    $nearlyStationNo = $stations[0]['station_no'];
                                    //距离最近站是第一站，则将当前站设置为1，
                                    if ($nearlyStationNo == 1) {
                                        $stationIndex = 1;
                                        $map[$busNo]['index'] = $stationIndex;
                                    } else {
                                        //否则，认为是最近站点的前一站，无法精确确定，理想情况
                                        $stationIndex = $nearlyStationNo - 1;
                                        $map[$busNo]['index'] = $stationIndex;
                                    }
//                                    echo " <br>** " . ($offTime) . $stationIndex . " 靠近了" . $stations[0]['station_name'] . $stations[0]['station_no'];
//                                    echo " 距离该点 " . $stations[0]['dictance'];
//                                    echo " 第二近的站是 " . $stations[1]['station_no'] . " :" . $stations[1]['station_name'];

                                } else {

//                                    echo " <br>** " . $stationIndex . " 靠近了" . $stations[0]['station_name'] . $stations[0]['station_no'];
//                                    echo " 距离该点 " . $stations[0]['dictance'];
//                                    echo " 第二近的站是 " . $stations[1]['station_no'] . " :" . $stations[1]['station_name'];

                                }
                            }
                        } else {
                            //没有站点相关信息，可能是首次进入的。可能是换线的
                            //

                            if ($stations[0]['dictance'] > 2000) {
                                echo '该车可能换线了！';
                            } else {
//                                echo " " . $currPosition;
//                                echo " 与站点号" . $stations[0]['station_no'] . $stations[0]['station_name'] . "最近！";
//                                echo " 距离该点 " . $stations[0]['dictance'];

                            }
                        }

                        $map[$busNo]["inStation"] = false;
                        $map[$busNo]['lastStations'] = $stations;
                    }


                    $map[$busNo]["lastInfos"] = $d;
                } else {
                    // 还没有该车记录
                    $map[$busNo] = array();
                    $map[$busNo]["number"] = 1;

                    $map[$busNo]["lastInfos"] = $d;
                    $map[$busNo]["firstInfos"] = $d;
//              判断线路号是否有效，无效的要记录
                    $lineInfos = $this->getStationInfos($d["line_no"], $d['direction']);
                    $map[$busNo]['dir'.$d['direction']]["lineInfos"] = $lineInfos;
//                next_station = (2,34),一共有34站，下一站信息只能统计到33站，
                    // 即下一站为34时，有可能车已经到站了。
                    // 当前车站点，如果当前车在 倒数第二站时，则有可能该车已到站了。
                    $currPosition = $d['next_station'] - 1;


                    echo ' 首次出现 No.' . $busNo;
                    echo ' 当前所在站序号：(' . $currPosition . "/" . count($lineInfos) . ")";

                    //当前站点非最后项
                    if ($currPosition < count($lineInfos) - 1) {
                        $station = $lineInfos[$currPosition - 1];
                        $stationNext = $lineInfos[$currPosition];
//                    echo $station;
                        $d = $gpsUtil->wgs2bd($d);
                        $dic = $gpsUtil->distance($d['lat'], $d['lng'], $station['lat'], $station['lng']);
                        $dicNext = $gpsUtil->distance($d['lat'], $d['lng'], $stationNext['lat'], $stationNext['lng']);
                        echo '距离该点：' . $dic;
                        echo '距离下一点：' . $dicNext;
                        echo '总距离:' . ($dic + $dicNext);

                        //距离当前站距离
                        $map[$busNo]['distance'] = $dic;


                    } else {

                    }
                    if ($lineInfos) {
                        echo " (" . $lineInfos[0]['line_name'] . ")";
                    } else {
                        echo " (未找到匹配项，line_no是：" . $d["line_no"] . ") ";
                    }
                    echo '<br>';
                }
            }
            // 该车存在记录

        }
        echo '<br>';

        foreach ($map as $k => $val) {
            echo "车ID:" . $k . " 出现次数:" . $val["number"] . "首次上报时间：" . $this->ToDateTimeString($val["firstInfos"]['time']) . " 最后上报时间：" . $this->ToDateTimeString($val["lastInfos"]['time']) . "<br>";
        }
    }

    /**
     * 通过线路号与方向获取站点信息，返回数组结构
     * @param $lineNo
     * @param $direction
     * @return false|\PDOStatement|string|\think\Collection
     */
    private function getStationInfos($lineNo, $direction)
    {
        $lineInfos = model('bus_line_station_view');
        $datas = $lineInfos
            ->where('direction', $direction)
            ->where('line_no', $lineNo)
            ->order('station_no', 'asc')
            ->select();
//        $this->displayArr($datas);
        return $datas;
    }

    //显示数组
    private function displayArr($arr)
    {
        foreach ($arr as $k => $v) {
            echo "[" . $k . ":" . $v . "]<br>";
        }
    }

    private function ToDateTimeString($time)
    {
        return Date('Y-m-d H:i:s', $time);
    }

    private function ToTimeString($time)
    {
        return Date('H:i:s', $time);

    }

    /**
     *
     * @param $AllStations 当前线路所有站点 数组
     * @param $lat 原始经纬度
     * @param $lng 原始经纬度
     * return 最近站点及第二近站点信息，按照距离排序的。
     */
    private function getLatestStations($AllStations, $lat, $lng)
    {
        $minDistance = 999999;
        $item['lat'] = $lat;
        $item['lng'] = $lng;
        $gpsUtil = new GpsUtil();
        $item = $gpsUtil->wgs2bd($item);
        $minStation = null;
        $minStation2 = null;
        foreach ($AllStations as $s) {
            $dic = $gpsUtil->distance($item['lat'], $item['lng'], $s['lat'], $s['lng']);
            if ($minDistance > $dic) {
                $minDistance = $dic;
                $minStation2 = $minStation;
                $minStation = $s;
                $minStation['dictance'] = $dic;
            }
        }
        return array($minStation, $minStation2);

    }

    /***
     * 判断是否在 6:00 - 21:00之间
     * @param $time 时间戳
     */
    private function isValidTime($time)
    {
//        echo $time;
        if ($time) {
            $d = (int)Date('H', $time);
            return ($d >= 6 && $d <= 22);
        } else {
            return false;
        }

    }

    /**
     * 判断是否是有效GPS数据
     * @param $gps
     *
     * @return bool
     */
    private function isValidGps($gps)
    {
        // 校验时间
        if (!$this->isValidTime($gps['time'])) {
//            echo 'GPS 数据不在有效时间内（6-22点之间）';
            return false;
        }
        return true;
    }

    /**
     * 处理原始GPS数据
     * @param $gps
     * @return mixed
     */
    private function processGps($gps)
    {
        $gps['lat'] /= 60;
        $gps['lng'] /= 60;
        return $gps;
    }

    /**
     * 与stn进行比对
     * @param $busNo 车no
     * @param $direction 方向
     * @param $StationNo 当前站点序号
     * @param $flag 到站还是离站 0||1
     * @param $time 上报时间
     */
    private function compareWithSTN($busNo,$direction,$StationNo,$flag,$time){
        $stn = db('stn');
        $datas = $stn
            ->where('bus_no',$busNo)
            ->where('direction',$direction)
            ->where('station_no',$StationNo)
            ->where('flag',$flag)
//            ->where('stn_dt','between',"'".($time-30).",".($time+30)."'")
        ->where('stn_dt','>',$time-30)
        ->where('stn_dt','<',$time+30)
        ->select();
        $flagDesc = array('到站','离站');
        foreach($datas as $d){
            echo "<br>";
            echo " STN ".$StationNo.$flagDesc[$flag]."时间：".$this->ToDateTimeString($d['stn_dt']);
            echo " GPSTIME -  STNTIME =：".($time-$d['stn_dt']).' 秒';
        }
        echo "<br>";

//        dump($datas);
    }
}
